﻿#include "LuaSysThread.h"
#include "luaobj/Luaobj.h"
#include "ZScheduler.h"

extern void RegisterExtendLibs(LuaState* L);

namespace ZuiLib
{

unsigned int s_threadId = 0;

LuaSysThread::LuaSysThread()
	:m_luaState(NULL), m_quit(true), m_id(++s_threadId)
{
	m_mutex = SDL_CreateMutex();
	m_SleepMutex = SDL_CreateMutex();
	m_SleepCondition = SDL_CreateCond();
}

LuaSysThread::~LuaSysThread()
{
	//如果没有退出则
	if (!m_quit)
		Quit();

	SDL_DestroyMutex(m_mutex);
	SDL_DestroyMutex(m_SleepMutex);
	SDL_DestroyCond(m_SleepCondition);

	while (!m_queue.empty())
	{
		delete m_queue.front();
		m_queue.pop();
	}
}

void LuaSysThread::Start()
{
	if (m_quit)
	{
		m_quit = false;
		m_thread = SDL_CreateThread(_ThreadProc,NULL, this);
	}
}


void LuaSysThread::Run(RunParam *param)
{
	SDL_LockMutex(m_mutex);
	m_queue.push(param);
	SDL_UnlockMutex(m_mutex);
	SDL_CondSignal(m_SleepCondition);
}


void LuaSysThread::Quit()
{
	if (!m_quit)
	{
		m_quit = true;
		SDL_CondSignal(m_SleepCondition);
		int rslt = 0;
		SDL_WaitThread(m_thread, &rslt);
	}
}


void LuaSysThread::OnRunning()
{
	_initLua();
	while (!m_quit)
	{
		SDL_CondWaitTimeout(m_SleepCondition, m_SleepMutex,100);
		RunParam* param = _popRunParam();
		while (param)
		{
			m_luaState->setGlobal("arg", m_luaState->newString(param->param.c_str(), param->param.length()));
			LuaObject lreturn = m_luaState->doString(param->script.c_str());
			ZRefCountedPtr<ReturnParam> returnParam = new ZRefCountedObject<ReturnParam>();
			returnParam->reqid = param->reqid;
			returnParam->threadid = m_id;
			returnParam->param = lreturn.toString();
			_onReturn(returnParam);
			delete param;
			param = _popRunParam();
		}
	}
	_releaseLua();
}

void LuaSysThread::_initLua()
{
	m_luaState = new LuaOwnerState();
	RegisterExtendLibs(m_luaState);
}


void LuaSysThread::_releaseLua()
{
	delete m_luaState;
	m_luaState = NULL;
}


int LuaSysThread::_ThreadProc(void* lpParameter)
{
	((LuaSysThread*)lpParameter)->OnRunning();
	return 0;
}

void LuaSysThread::_onReturn(ReturnParam* param)
{
	ZuiLib::ZApplication::Instance()->PostSchedule(param, schedule_selector_void(ReturnParam::RunOnUIThread));
}

LuaSysThread::RunParam* LuaSysThread::_popRunParam()
{
	RunParam* param = NULL;
	SDL_LockMutex(m_mutex);
	if (!m_queue.empty())
	{
		param = m_queue.front();
		m_queue.pop();
	}
	SDL_UnlockMutex(m_mutex);
	return param;
}


//在ui线程运行
void LuaSysThread::ReturnParam::RunOnUIThread()
{
	LuaState* L = ZScriptEngine::Instance()->GetLuaState();
	LuaTable lthread = LuaTable(L->getRegistery("LuaThread")).getTable(threadid);

	if (lthread.isValid())
	{
		LuaFunction func=lthread.getTable(reqid);
		if (func.isValid())
		{
			func(param);
		}
		lthread.setTable(reqid, luaNil);
	}
}



class LuaThreadApi :public LuaClass<LuaSysThread>
{
public:
	void ctor(LuaFuncState& L)
	{
		m_reqid=0;
		pThis = new LuaSysThread();
		LuaTable ltab= L.getRegistery("LuaThread");
		ltab.setTable(pThis->GetID(), L.newTable());//run的回调函数存在该表中
	}

	int start(LuaFuncState& L)
	{
		pThis->Start();
		return 0;
	}

	int run(LuaFuncState& L)
	{
        LuaSysThread::RunParam * param = new LuaSysThread::RunParam();
		param->reqid = ++m_reqid;
		param->script = L.arg(0).toString();
		param->param = L.arg(1).toString();

		if (L.arg(2).isFunction())
		{
			LuaTable ltab = LuaTable(L.getRegistery("LuaThread")).getTable(pThis->GetID());
			if (ltab.isTable())
			{
				ltab.setTable(param->reqid, L.arg(2));
			}
		}
		pThis->Run(param);
		return 0;
	}

	int quit(LuaFuncState& L)
	{
		//回调函数置空
		LuaTable ltab = L.getRegistery("LuaThread");
		ltab.setTable(pThis->GetID(), luaNil);
		pThis->Quit();
		delete pThis;
		pThis = NULL;
		return 0;
	}

	BEGIN_MAP_FUNC(LuaThreadApi)
		DECLARE_FUNC(start),
		DECLARE_FUNC(run),
		DECLARE_FUNC(quit),
	END_MAP_FUNC
private:
	unsigned int m_reqid;
};


void RegisterLuaThread(LuaState* L)
{
	L->setRegistry("LuaThread", L->newTable());
	LuaRegister<LuaThreadApi>::Register(L->getLuaState());
}

}//namespace
